/**
 * 图片处理工具模块
 * 提供图片处理相关功能，包括压缩、裁剪、滤镜、格式转换等
 */

/**
 * 创建Canvas元素
 * @param {number} width 宽度
 * @param {number} height 高度
 * @returns {Object} { canvas, ctx }
 */
function createCanvas(width, height) {
  const canvas = document.createElement('canvas');
  canvas.width = width;
  canvas.height = height;
  const ctx = canvas.getContext('2d');
  return { canvas, ctx };
}

/**
 * Canvas转Blob的兼容性方法
 * @param {HTMLCanvasElement} canvas Canvas元素
 * @param {string} mimeType MIME类型
 * @param {number} quality 质量
 * @returns {Promise<Blob>} Blob对象
 */
function canvasToBlob(canvas, mimeType = 'image/jpeg', quality = 0.8) {
  return new Promise((resolve, reject) => {
    try {
      // 优先使用原生toBlob方法
      if (canvas.toBlob) {
        canvas.toBlob((blob) => {
          if (blob) {
            resolve(blob);
          } else {
            // toBlob失败，使用降级方案
            fallbackToDataURL();
          }
        }, mimeType, quality);
      } else {
        // 浏览器不支持toBlob，使用降级方案
        fallbackToDataURL();
      }

      function fallbackToDataURL() {
        try {
          const dataURL = canvas.toDataURL(mimeType, quality);
          const blob = dataURLToBlob(dataURL);
          resolve(blob);
        } catch (e) {
          reject(new Error('Canvas转换失败: ' + e.message));
        }
      }
    } catch (e) {
      reject(new Error('Canvas处理失败: ' + e.message));
    }
  });
}

/**
 * DataURL转Blob
 * @param {string} dataURL DataURL字符串
 * @returns {Blob} Blob对象
 */
function dataURLToBlob(dataURL) {
  const parts = dataURL.split(',');
  const mimeType = parts[0].match(/:(.*?);/)[1];
  const base64 = parts[1];

  // 解码base64
  const binary = atob(base64);
  const array = new Uint8Array(binary.length);

  for (let i = 0; i < binary.length; i++) {
    array[i] = binary.charCodeAt(i);
  }

  return new Blob([array], { type: mimeType });
}

/**
 * 加载图片
 * @param {string|File|Blob} source 图片源
 * @returns {Promise<HTMLImageElement>} 图片元素
 */
export function loadImage(source) {
  return new Promise((resolve, reject) => {
    const img = new Image();
    img.crossOrigin = 'anonymous';

    img.onload = () => resolve(img);
    img.onerror = () => reject(new Error('图片加载失败'));

    if (typeof source === 'string') {
      img.src = source;
    } else if (source instanceof File || source instanceof Blob) {
      img.src = URL.createObjectURL(source);
    } else {
      reject(new Error('不支持的图片源类型'));
    }
  });
}

/**
 * 压缩图片
 * @param {string|File|Blob|HTMLImageElement} source 图片源
 * @param {Object} options 压缩选项
 * @param {number} options.quality 压缩质量 0-1，默认0.8
 * @param {number} options.maxWidth 最大宽度
 * @param {number} options.maxHeight 最大高度
 * @param {string} options.mimeType 输出MIME类型，默认'image/jpeg'
 * @returns {Promise<Blob>} 压缩后的图片Blob
 */
export async function compressImage(source, options = {}) {
  const {
    quality = 0.8,
    maxWidth = 1920,
    maxHeight = 1080,
    mimeType = 'image/jpeg'
  } = options;

  const img = source instanceof HTMLImageElement ? source : await loadImage(source);

  // 计算压缩后的尺寸
  let { width, height } = img;

  if (width > maxWidth) {
    height = (height * maxWidth) / width;
    width = maxWidth;
  }

  if (height > maxHeight) {
    width = (width * maxHeight) / height;
    height = maxHeight;
  }

  const { canvas, ctx } = createCanvas(width, height);
  ctx.drawImage(img, 0, 0, width, height);

  return canvasToBlob(canvas, mimeType, quality);
}

/**
 * 裁剪图片
 * @param {string|File|Blob|HTMLImageElement} source 图片源
 * @param {Object|number} cropAreaOrX 裁剪区域对象或起始x坐标
 * @param {number} y 起始y坐标（当第二个参数为数字时）
 * @param {number} width 裁剪宽度（当第二个参数为数字时）
 * @param {number} height 裁剪高度（当第二个参数为数字时）
 * @param {string} mimeType 输出MIME类型
 * @returns {Promise<Blob>} 裁剪后的图片Blob
 */
export async function cropImage(source, cropAreaOrX, y, width, height, mimeType = 'image/jpeg') {
  const img = source instanceof HTMLImageElement ? source : await loadImage(source);

  let cropX, cropY, cropWidth, cropHeight, outputMimeType;

  // 支持两种调用方式
  if (typeof cropAreaOrX === 'object') {
    // 方式1：cropImage(source, {x, y, width, height}, mimeType)
    ({ x: cropX, y: cropY, width: cropWidth, height: cropHeight } = cropAreaOrX);
    outputMimeType = y || 'image/jpeg'; // 第三个参数是mimeType
  } else {
    // 方式2：cropImage(source, x, y, width, height, mimeType)
    cropX = cropAreaOrX;
    cropY = y;
    cropWidth = width;
    cropHeight = height;
    outputMimeType = mimeType;
  }

  // 参数验证
  if (cropX < 0 || cropY < 0 || cropWidth <= 0 || cropHeight <= 0) {
    throw new Error('裁剪参数无效');
  }

  if (cropX + cropWidth > img.width || cropY + cropHeight > img.height) {
    throw new Error('裁剪区域超出图片范围');
  }

  const { canvas, ctx } = createCanvas(cropWidth, cropHeight);

  // 正确的drawImage参数：(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight)
  // sx, sy: 源图片中的起始坐标
  // sWidth, sHeight: 源图片中要裁剪的区域大小
  // dx, dy: 目标画布中的起始坐标
  // dWidth, dHeight: 目标画布中的绘制大小
  ctx.drawImage(img, cropX, cropY, cropWidth, cropHeight, 0, 0, cropWidth, cropHeight);

  return canvasToBlob(canvas, outputMimeType);
}

/**
 * 调整图片尺寸
 * @param {string|File|Blob|HTMLImageElement} source 图片源
 * @param {Object} size 新尺寸
 * @param {number} size.width 新宽度
 * @param {number} size.height 新高度
 * @param {string} mimeType 输出MIME类型
 * @returns {Promise<Blob>} 调整后的图片Blob
 */
export async function resizeImage(source, size, mimeType = 'image/jpeg') {
  const img = source instanceof HTMLImageElement ? source : await loadImage(source);
  const { width, height } = size;

  const { canvas, ctx } = createCanvas(width, height);
  ctx.drawImage(img, 0, 0, width, height);

  return canvasToBlob(canvas, mimeType);
}

/**
 * 旋转图片
 * @param {string|File|Blob|HTMLImageElement} source 图片源
 * @param {number} angle 旋转角度（度）
 * @param {string} mimeType 输出MIME类型
 * @returns {Promise<Blob>} 旋转后的图片Blob
 */
export async function rotateImage(source, angle, mimeType = 'image/jpeg') {
  const img = source instanceof HTMLImageElement ? source : await loadImage(source);
  const rad = (angle * Math.PI) / 180;

  // 计算旋转后的画布尺寸
  const cos = Math.abs(Math.cos(rad));
  const sin = Math.abs(Math.sin(rad));
  const newWidth = img.width * cos + img.height * sin;
  const newHeight = img.width * sin + img.height * cos;

  const { canvas, ctx } = createCanvas(newWidth, newHeight);

  // 移动到画布中心，旋转，然后绘制图片
  ctx.translate(newWidth / 2, newHeight / 2);
  ctx.rotate(rad);
  ctx.drawImage(img, -img.width / 2, -img.height / 2);

  return canvasToBlob(canvas, mimeType);
}

/**
 * 翻转图片
 * @param {string|File|Blob|HTMLImageElement} source 图片源
 * @param {string} direction 翻转方向：'horizontal'（水平）或 'vertical'（垂直）
 * @param {string} mimeType 输出MIME类型
 * @returns {Promise<Blob>} 翻转后的图片Blob
 */
export async function flipImage(source, direction = 'horizontal', mimeType = 'image/jpeg') {
  const img = source instanceof HTMLImageElement ? source : await loadImage(source);
  const { canvas, ctx } = createCanvas(img.width, img.height);

  if (direction === 'horizontal') {
    ctx.scale(-1, 1);
    ctx.drawImage(img, -img.width, 0);
  } else if (direction === 'vertical') {
    ctx.scale(1, -1);
    ctx.drawImage(img, 0, -img.height);
  } else {
    throw new Error('不支持的翻转方向');
  }

  return canvasToBlob(canvas, mimeType);
}

/**
 * 添加滤镜效果
 * @param {string|File|Blob|HTMLImageElement} source 图片源
 * @param {string} filter CSS滤镜字符串
 * @param {string} mimeType 输出MIME类型
 * @returns {Promise<Blob>} 添加滤镜后的图片Blob
 */
export async function applyFilter(source, filter, mimeType = 'image/jpeg') {
  const img = source instanceof HTMLImageElement ? source : await loadImage(source);
  const { canvas, ctx } = createCanvas(img.width, img.height);

  ctx.filter = filter;
  ctx.drawImage(img, 0, 0);

  return canvasToBlob(canvas, mimeType);
}

/**
 * 调整图片亮度
 * @param {string|File|Blob|HTMLImageElement} source 图片源
 * @param {number} brightness 亮度值（0-200，100为原始亮度）
 * @param {string} mimeType 输出MIME类型
 * @returns {Promise<Blob>} 调整后的图片Blob
 */
export function adjustBrightness(source, brightness = 100, mimeType = 'image/jpeg') {
  return applyFilter(source, `brightness(${brightness}%)`, mimeType);
}

/**
 * 调整图片对比度
 * @param {string|File|Blob|HTMLImageElement} source 图片源
 * @param {number} contrast 对比度值（0-200，100为原始对比度）
 * @param {string} mimeType 输出MIME类型
 * @returns {Promise<Blob>} 调整后的图片Blob
 */
export function adjustContrast(source, contrast = 100, mimeType = 'image/jpeg') {
  return applyFilter(source, `contrast(${contrast}%)`, mimeType);
}

/**
 * 调整图片饱和度
 * @param {string|File|Blob|HTMLImageElement} source 图片源
 * @param {number} saturation 饱和度值（0-200，100为原始饱和度）
 * @param {string} mimeType 输出MIME类型
 * @returns {Promise<Blob>} 调整后的图片Blob
 */
export function adjustSaturation(source, saturation = 100, mimeType = 'image/jpeg') {
  return applyFilter(source, `saturate(${saturation}%)`, mimeType);
}

/**
 * 模糊图片
 * @param {string|File|Blob|HTMLImageElement} source 图片源
 * @param {number} radius 模糊半径（像素）
 * @param {string} mimeType 输出MIME类型
 * @returns {Promise<Blob>} 模糊后的图片Blob
 */
export function blurImage(source, radius = 5, mimeType = 'image/jpeg') {
  return applyFilter(source, `blur(${radius}px)`, mimeType);
}

/**
 * 转换为灰度图片
 * @param {string|File|Blob|HTMLImageElement} source 图片源
 * @param {string} mimeType 输出MIME类型
 * @returns {Promise<Blob>} 灰度图片Blob
 */
export function toGrayscale(source, mimeType = 'image/jpeg') {
  return applyFilter(source, 'grayscale(100%)', mimeType);
}

/**
 * 转换为棕褐色图片
 * @param {string|File|Blob|HTMLImageElement} source 图片源
 * @param {string} mimeType 输出MIME类型
 * @returns {Promise<Blob>} 棕褐色图片Blob
 */
export function toSepia(source, mimeType = 'image/jpeg') {
  return applyFilter(source, 'sepia(100%)', mimeType);
}

/**
 * 反转图片颜色
 * @param {string|File|Blob|HTMLImageElement} source 图片源
 * @param {string} mimeType 输出MIME类型
 * @returns {Promise<Blob>} 反转后的图片Blob
 */
export function invertImage(source, mimeType = 'image/jpeg') {
  return applyFilter(source, 'invert(100%)', mimeType);
}

/**
 * 获取图片主要颜色
 * @param {string|File|Blob|HTMLImageElement} source 图片源
 * @param {number} sampleSize 采样大小，默认10
 * @returns {Promise<Array<Array<number>>>} 主要颜色数组，每个颜色为[r,g,b]格式
 */
export async function getDominantColors(source, sampleSize = 10) {
  const img = source instanceof HTMLImageElement ? source : await loadImage(source);
  const { canvas, ctx } = createCanvas(img.width, img.height);

  ctx.drawImage(img, 0, 0);
  const imageData = ctx.getImageData(0, 0, img.width, img.height);
  const data = imageData.data;

  const colorMap = new Map();

  // 采样像素
  for (let i = 0; i < data.length; i += 4 * sampleSize) {
    const r = data[i];
    const g = data[i + 1];
    const b = data[i + 2];
    const a = data[i + 3];

    if (a > 128) { // 忽略透明像素
      const color = `${r},${g},${b}`;
      colorMap.set(color, (colorMap.get(color) || 0) + 1);
    }
  }

  // 按出现频率排序
  const sortedColors = Array.from(colorMap.entries())
    .sort((a, b) => b[1] - a[1])
    .slice(0, 5)
    .map(([color]) => color.split(',').map(Number));

  return sortedColors;
}

/**
 * 获取图片平均颜色
 * @param {string|File|Blob|HTMLImageElement} source 图片源
 * @returns {Promise<Array<number>>} 平均颜色 [r,g,b]
 */
export async function getAverageColor(source) {
  const img = source instanceof HTMLImageElement ? source : await loadImage(source);
  const { canvas, ctx } = createCanvas(img.width, img.height);

  ctx.drawImage(img, 0, 0);
  const imageData = ctx.getImageData(0, 0, img.width, img.height);
  const data = imageData.data;

  let r = 0, g = 0, b = 0, count = 0;

  for (let i = 0; i < data.length; i += 4) {
    if (data[i + 3] > 128) { // 忽略透明像素
      r += data[i];
      g += data[i + 1];
      b += data[i + 2];
      count++;
    }
  }

  return count > 0 ? [
    Math.round(r / count),
    Math.round(g / count),
    Math.round(b / count)
  ] : [0, 0, 0];
}

/**
 * 创建缩略图
 * @param {string|File|Blob|HTMLImageElement} source 图片源
 * @param {Object} options 选项
 * @param {number} options.width 缩略图宽度，默认150
 * @param {number} options.height 缩略图高度，默认150
 * @param {string} options.fit 适应方式：'cover'（裁剪）或'contain'（包含），默认'cover'
 * @param {string} mimeType 输出MIME类型
 * @returns {Promise<Blob>} 缩略图Blob
 */
export async function createThumbnail(source, options = {}, mimeType = 'image/jpeg') {
  const {
    width = 150,
    height = 150,
    fit = 'cover'
  } = options;

  const img = source instanceof HTMLImageElement ? source : await loadImage(source);
  const { canvas, ctx } = createCanvas(width, height);

  let sx = 0, sy = 0, sw = img.width, sh = img.height;
  let dx = 0, dy = 0, dw = width, dh = height;

  if (fit === 'cover') {
    // 按比例缩放并居中裁剪
    const scale = Math.max(width / img.width, height / img.height);
    sw = width / scale;
    sh = height / scale;
    sx = (img.width - sw) / 2;
    sy = (img.height - sh) / 2;
  } else if (fit === 'contain') {
    // 按比例缩放并完整显示
    const scale = Math.min(width / img.width, height / img.height);
    dw = img.width * scale;
    dh = img.height * scale;
    dx = (width - dw) / 2;
    dy = (height - dh) / 2;
  }

  ctx.drawImage(img, sx, sy, sw, sh, dx, dy, dw, dh);

  return canvasToBlob(canvas, mimeType);
}

/**
 * 给图片添加水印
 * @param {string|File|Blob|HTMLImageElement} source 图片源
 * @param {string} watermarkText 水印文字
 * @param {Object} options 水印选项
 * @param {string} options.position 位置：'top-left', 'top-right', 'bottom-left', 'bottom-right', 'center'
 * @param {string} options.font 字体，默认'20px Arial'
 * @param {string} options.color 颜色，默认'rgba(255,255,255,0.5)'
 * @param {number} options.padding 边距，默认20
 * @param {string} mimeType 输出MIME类型
 * @returns {Promise<Blob>} 添加水印后的图片Blob
 */
export async function addWatermark(source, watermarkText, options = {}, mimeType = 'image/jpeg') {
  const {
    position = 'bottom-right',
    font = '20px Arial',
    color = 'rgba(255,255,255,0.5)',
    padding = 20
  } = options;

  const img = source instanceof HTMLImageElement ? source : await loadImage(source);
  const { canvas, ctx } = createCanvas(img.width, img.height);

  ctx.drawImage(img, 0, 0);

  // 设置水印样式
  ctx.font = font;
  ctx.fillStyle = color;
  ctx.textBaseline = 'top';

  // 计算文字尺寸
  const textMetrics = ctx.measureText(watermarkText);
  const textWidth = textMetrics.width;
  const textHeight = parseInt(font);

  // 计算位置
  let x, y;
  switch (position) {
    case 'top-left':
      x = padding;
      y = padding;
      break;
    case 'top-right':
      x = img.width - textWidth - padding;
      y = padding;
      break;
    case 'bottom-left':
      x = padding;
      y = img.height - textHeight - padding;
      break;
    case 'bottom-right':
      x = img.width - textWidth - padding;
      y = img.height - textHeight - padding;
      break;
    case 'center':
      x = (img.width - textWidth) / 2;
      y = (img.height - textHeight) / 2;
      break;
    default:
      x = img.width - textWidth - padding;
      y = img.height - textHeight - padding;
  }

  ctx.fillText(watermarkText, x, y);

  return canvasToBlob(canvas, mimeType);
}

/**
 * 获取图片信息
 * @param {string|File|Blob|HTMLImageElement} source 图片源
 * @returns {Promise<Object>} 图片信息
 */
export async function getImageInfo(source) {
  const img = source instanceof HTMLImageElement ? source : await loadImage(source);

  return {
    width: img.width,
    height: img.height,
    aspectRatio: img.width / img.height,
    orientation: img.width > img.height ? 'landscape' : img.height > img.width ? 'portrait' : 'square'
  };
}